/******************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks
 * @brief   C++ streams.
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 ******************************************************************************/

#define BASE_STREAM_FUNCS_CC 1
#include <fstream>
#include "base/module.hh"
#include "base/stream_funcs.hh"
#include "base/file.hh"

namespace base {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////  functions  //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*******************************************************************************
 * 
 *******************************************************************************/
bool StreamOpen( std::fstream& fs, std::ios::openmode bits, const string& filename )
{
    // Open stream in binary mode (but this still does NOT mean unformatted mode).
    bits |= std::ios::binary;

    // Try opening a stream to a file.
    // For the open-for-writing case, first try to open the file without the truncate bit.
    // But some iostream implementations might fail if the file doesn't exist.
    fs.open( filename.c_str(), bits );
    if ( (not fs.good())                     // if error
     and (bits & std::ios::out)              // if output stream
     and (not (bits & std::ios::trunc)) )    // if truncate not already set
    {
        // This might be the file-doesn't-exist case depending
        // on the iostream implementation.  Retry with truncate bit.
        fs.clear();
        fs.open( filename.c_str(), bits | std::ios::trunc );
    }

    return fs.good();
}

/*******************************************************************************
 * 
 *******************************************************************************/
bool StreamReadLine( std::istream& strm, string& line )
{
    line.erase();
    char c = 0;
    while ( strm.good() and (c = strm.get()) != '\n' )
    {
        line += c;
    }
    return strm.good();
}

/*******************************************************************************
 * 
 *******************************************************************************/
bool StreamToNextLine( std::istream& strm )
{
    while ( strm.good() and (strm.get() != '\n') ) { }
    return strm.good();
}

/*******************************************************************************
 * 
 *******************************************************************************/
bool StreamPeek( std::istream& strm, const string& word )
{
    bool result = false;

    // Save read position.
    std::ios::pos_type pos = strm.tellg();

    try
    {
        // Read char-by-char into a buf
        string buf;
        for ( uint i = 0; i < word.size(); ++i )
        {
            const char c = char(strm.get());
            if ( not strm.good() )
                break;

            switch ( c )
            {
                case CHAR_LF: case CHAR_CR: case ' ': case '\t':
                {
                    --i;  // don't append whitespace to buf[]
                    continue;
                }
                break;

                default:
                {
                    buf += char(c);
                }
                break;
            }

            if ( buf[i] != word[i] )  // mismatch?
                break;
        }
        result = (buf == word) and strm.good();
    }
    catch (...)
    {
        result = false;
    }

    // Restore read position.
    strm.seekg( pos );

    return result;
}

} // namespace base
